#include "Storage.h"

Storage* Storage::theOnlyStorage = NULL;

Storage::Storage(void){
}

string Storage::addTask(FloatingTask* newTask){
	taskList.push_back(newTask);
	message = CommonConstant::MESSAGE_CREATED
			+ CommonConstant::END_LINE
			+ newTask->taskInfomation();
			  
	return message;
}

string Storage::retrieveTaskStringInfo(int index){
	try{
		checkRange(index);
		return taskList[index]->taskInfomation();
	} catch(OutOfRange &outOfRange){
		return errorMessageOutOfRange(outOfRange.returnString());
	}		
}

FloatingTask* Storage::retrieveTask(int index){
	try{
		checkRange(index);
	} catch(OutOfRange &OutOfRange)
	{
		return OutOfRange.returnNullPointer();
	}
	return taskList[index];
}

string Storage::updateTask(int index,FloatingTask* newtask){
	try{
		checkRange(index);
		taskList[index]=newtask;

		message = CommonConstant::MESSAGE_UPDATED 
				  + CommonConstant::END_LINE 
				  + taskList[index]->taskInfomation();

		return message;
	} catch(OutOfRange &outOfRange){
		return errorMessageOutOfRange(outOfRange.returnString());
	}		
}

string Storage::deleteTask(int index){
	try{
		checkRange(index);
		taskList.erase(taskList.begin()+index);

		for(unsigned int i=CommonConstant::INDEX_ZERO;i<taskList.size();i++){
			taskList[i]->setIndex(i);
		}

		sprintf_s(CommonConstant::buffer,CommonConstant::MESSAGE_DELETED.c_str(),index);
		return CommonConstant::buffer;
	} catch(OutOfRange &outOfRange){
		return errorMessageOutOfRange(outOfRange.returnString());
	}		
}

string Storage::insertTask(int index, FloatingTask* newtask){
	taskList.insert(taskList.begin()+index, newtask);
	return CommonConstant::MESSAGE_INSERTED;
}

vector <FloatingTask*> Storage::getTaskList(){ 
	return taskList; 
}

int Storage::size(){
	return taskList.size(); 
}

char Storage::retrieveTaskType(int index){
	try{
		checkRange(index);
		return taskList[index]->getTaskType();
	}catch(OutOfRange &outOfRange){
		return outOfRange.returnCharacter();
	}
}

Storage* Storage::getInstance(){
	if(!theOnlyStorage){
		theOnlyStorage = new Storage();
	} 
	return theOnlyStorage;
}

void Storage::checkRange(int index){
	if(index >= size() || index < CommonConstant::INDEX_ZERO){
		throw OutOfRange();
	}
}

string Storage::errorMessageOutOfRange(string message){
	message += CommonConstant::END_LINE;

	if(size() == CommonConstant::INDEX_ZERO){
		message	+= CommonConstant::MESSAGE_NO_TASK;
	} else{
		int lastIndex = size();
		lastIndex--;
		sprintf_s(CommonConstant::buffer,CommonConstant::MESSAGE_VALID_INDEX_FORMAT.c_str(),lastIndex);
		message += CommonConstant::buffer;
	}
	return message;
}

Storage::~Storage(void){
	while(size() > CommonConstant::INDEX_ZERO){
		delete taskList[CommonConstant::INDEX_ZERO];
		taskList[CommonConstant::INDEX_ZERO] = NULL;
		deleteTask(CommonConstant::INDEX_ZERO);
	}
}

OutOfRange::OutOfRange(void){
}

OutOfRange::~OutOfRange(void){
}

const string OutOfRange::returnString() const{
	return CommonConstant::MESSAGE_INVALID_INDEX;
}

const char OutOfRange::returnCharacter() const{
	return CommonConstant::TASK_TYPE_INVALID;
}

FloatingTask* OutOfRange::returnNullPointer() const{
	return NULL;
}